Skip to content

Add depthz_image_transport: lossless depth compression (32FC1 and 16UC1) - #238

Open
facontidavide wants to merge 2 commits into
ros-perception:rollingfrom
facontidavide:dpred_image_transport
Open

Add depthz_image_transport: lossless depth compression (32FC1 and 16UC1)#238
facontidavide wants to merge 2 commits into
ros-perception:rollingfrom
facontidavide:dpred_image_transport

Conversation

@facontidavide

@facontidavide facontidavide commented Jul 2, 2026

Copy link
Copy Markdown

Embracing the fact that AI is taking my (our) job, I am contributing this specialized algorithm to compress depth images.

It is approaximately 10x faster than PNG (notoriously slow) and has 30% better compression, at least on my personal dataset (that is far from being exhaustive).

I think this has a great value for the community and I hope you can give it a look 😄

image

@facontidavide facontidavide changed the title Add dpred_image_transport: lossless 32FC1 depth compression Add dpred_image_transport: lossless depth compression Jul 2, 2026
@facontidavide
facontidavide force-pushed the dpred_image_transport branch from f2b9662 to baa7870 Compare July 2, 2026 20:46
@facontidavide facontidavide changed the title Add dpred_image_transport: lossless depth compression Add depthz_image_transport: lossless depth compression (32FC1 and 16UC1) Jul 2, 2026
@facontidavide
facontidavide marked this pull request as ready for review July 2, 2026 21:00
@mergify

mergify Bot commented Jul 2, 2026

Copy link
Copy Markdown

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

@facontidavide
facontidavide marked this pull request as draft July 6, 2026 12:08
@facontidavide

Copy link
Copy Markdown
Author

moving back to draft. I am realizing the current depth compression based on PNG is not lossless and this creates and anfair comparison between the two. refining the work a bit

@facontidavide
facontidavide force-pushed the dpred_image_transport branch from 439824b to 45d8a93 Compare July 6, 2026 12:51
image_transport plugin for depth images, vendoring the depth codec from
facontidavide/depth_image_compression.

By default 32FC1 is quantized to a configurable uniform grid
(<base_topic>.depthz.quantization, default 0.1 mm): every decoded pixel
is within +/- half a step of the input, invalid pixels (NaN/inf/<= 0)
are preserved and decode as NaN per REP 118, and the "qpred" payload
(MED prediction on the quantization codes, zigzag + LEB128 varint
residuals, zstd) has no 16-bit level limit, so arbitrarily fine steps
and long ranges are supported. Setting quantization to 0 selects the
bit-exact lossless mode: a value dictionary + 2D prediction ("dpred")
for images with up to 65536 distinct values, and a dictionary-free
float-total-order predictor ("fpred") beyond that. 16UC1 input is
always compressed losslessly ("dpred16").

On real full-precision stereo depth the default mode compresses better
than compressedDepth (PNG) while encoding and decoding several times
faster, with a much finer, explicitly bounded quantization error.

Implementation notes:
- Blobs are fully self-describing: method, dimensions, pixel format and
  quantization step are readable from the header without decompressing.
- Hot paths use runtime-dispatched AVX2 kernels next to scalar paths
  that emit bit-identical blobs (and are independent of the FPU
  rounding mode); decoding reconstructs along a wavefront.
- Steady-state encode/decode performs no heap allocation (thread-local
  scratch, bounded-by-header zstd decompression, per-thread contexts).
- Hostile/corrupt blobs are rejected before any allocation sized from
  untrusted fields; degenerate image sizes are handled; the test suite
  covers round trips, error bounds, and adversarial payloads under
  ASan/UBSan.
- benchmark/ contains an optional black-box perf tool (off by default,
  -DDEPTHZ_BUILD_BENCHMARK=ON) that drives any image_transport plugin
  end to end over frames extracted from MCAP bags.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@facontidavide
facontidavide force-pushed the dpred_image_transport branch from 445c5ad to 681f651 Compare July 6, 2026 13:08
@facontidavide

Copy link
Copy Markdown
Author

Update numbers.

Lossless approach if faster by compresses less than the former PNG approach, because PNG is lossy.

So I added a lossy algorithm where quantization is implicit and predicatable (config paramter).

Use can pick the one they prefer. it is faster, compresses better and has less quantization error, in some cases.

image

@facontidavide
facontidavide marked this pull request as ready for review July 6, 2026 13:15

@ahcorde ahcorde left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor comments, otherwise LGTM

Comment thread depthz_image_transport/README.md Outdated
)

# The vendored depth codec uses C++20 (std::countr_zero, std::endian).
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you mind to use ament_cmake_ros_core to set the cpp20 version ? It should be included in this other PR for the rest of the plugins

@@ -0,0 +1,13 @@
<library path="depthz_image_transport">
<class name="image_transport/depthz_pub" type="depthz_image_transport::DepthzPublisher" base_class_type="image_transport::PublisherPlugin">

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing

  <transport_name>depthz</transport_name>
  <message_type>sensor_msgs/msg/CompressedImage</message_type>

Comment on lines +1163 to +1164
parsed.header.width = get_u32(blob + pos);
parsed.header.height = get_u32(blob + pos + 4);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check if the height*height doesn't overflow?

Co-authored-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants